package top.yuhaitao.luence.controller.lucene;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.wltea.analyzer.lucene.IKAnalyzer;
import top.yuhaitao.luence.dbo.Sku;
import top.yuhaitao.luence.mapper.SkuBaseMapper;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Random;

/**
 * @author ht.yu
 */
@RestController
@RequestMapping("/sku")
public class SkuController {

    private static final String path = "D://lucene_index";


    @Resource
    private SkuBaseMapper skuBaseMapper;


    @RequestMapping("/selectDb")
    public String selectDb() {
        List<Sku> list = new LambdaQueryChainWrapper<>(skuBaseMapper).gt(Sku::getId, 0).list();
        return JSON.toJSONString(list);
    }


    @RequestMapping("/insert")
    public String insert() throws IOException {
        List<Sku> list = new LambdaQueryChainWrapper<>(skuBaseMapper).gt(Sku::getId, 0).list();

        LinkedList<Document> list1 = new LinkedList<>();

        for (Sku sku : list) {
            Document document = new Document();
            /**
             * 是否分词：不分词，没有意义
             * 是否索引：索引
             * 是否存储：存储
             */
            document.add(new StringField("id", String.valueOf(sku.getId()), Field.Store.YES)); // ✅ 存储值
            /**
             * 是否分词：分词，因为分词后有意义
             * 是否索引：索引，需哟根据名称进行搜索
             * 是否存储：存储
             */
            document.add(new TextField("name", sku.getName(), Field.Store.YES)); // YES = 存储
            /**
             * 是否分词：分词，如果需要在lucene中进行范围查询，底层算法需要
             * 是否索引：索引
             * 是否存储：存储
             */
            document.add(new IntPoint("price", sku.getPrice()));
            // IntPoint 没有索引功能，所以需要单独存储
            document.add(new StoredField("price", sku.getPrice())); // ✅ 存储值
            /**
             *
             * StringField 不分词，索引，存储
             * 是否分词：不分词 ， 不需要根据路径搜索，StringField
             * 是否索引：可以索引，也可以不索引
             * 是否存储：存存储
             */
            document.add(new StringField("image", sku.getImage(), Field.Store.YES));
            /**
             * StringField 不分词，索引，存储
             * 是否分词：不分词 ， 类别一般就是枚举，不索引
             * 是否索引：可以索引，也可以不索引
             * 是否存储：存存储
             */
            document.add(new StringField("categoryName", sku.getCategoryName(), Field.Store.YES));
            /**
             * StringField 不分词，索引，存储
             * 是否分词：不分词 ， 品牌一般就是枚举，不索引
             * 是否索引：可以索引，也可以不索引
             * 是否存储：存存储
             */
            document.add(new StringField("brandName", sku.getBrandName(), Field.Store.YES));

            document.add(new StringField("spec", sku.getSpec(), Field.Store.YES));

            // saleNum 同理
            document.add(new IntPoint("saleNum", sku.getSaleNum()));
            document.add(new StoredField("saleNum", sku.getSaleNum())); // ✅ 存储值
            list1.add(document);
        }

        // 1. 指定索引存储路径
        Directory directory = FSDirectory.open(Paths.get(path));

        // 使用智能分词模式
        Analyzer analyzer = new IKAnalyzer(false);


        // 3. 配置 IndexWriter
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        config.setOpenMode(IndexWriterConfig.OpenMode.CREATE); // 每次重新创建索引

        // 4. 创建 IndexWriter
        IndexWriter writer = new IndexWriter(directory, config);


        // 6. 添加文档到索引
        for (Document indexableFields : list1) {
            writer.addDocument(indexableFields);

        }
        writer.commit();
        writer.close();
        return JSON.toJSONString(list);
    }

    @RequestMapping("/select")
    public String select(@RequestParam(value = "name") String name) throws Exception {
        //、创建分词器
        Analyzer analyzer = new IKAnalyzer();
//        、创建查询对象
        QueryParser queryParser = new QueryParser("name", analyzer);


// 设置搜索关键词
        Query query = queryParser.parse(name);
///14. 创建Directory目录对象，指定索引库的位置
        Directory dir = FSDirectory.open(Paths.get(path));
///15. 创建输入流
        IndexReader reader = DirectoryReader.open(dir);
//        116. 创建搜索对象
        IndexSearcher indexSearcher = new IndexSearcher(reader);
//        、搜索并返回结果
        TopDocs topDocs = indexSearcher.search(query, 10);

//8.获取结果集System.out.println("======总记录数===="+ topDocs.totalHits)
///19、遍历结果

        List<Sku> skuList = new LinkedList<>();
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        if (scoreDocs != null) {
            for (ScoreDoc scoreDoc : scoreDocs) {
                int id = scoreDoc.doc;
                Document doc = indexSearcher.doc(id);
                Sku sku = new Sku();
                sku.setId((long) id);
                sku.setName(doc.get("name"));
                sku.setPrice(Integer.parseInt(Optional.ofNullable(doc.get("price")).orElse("0")));
                sku.setImage(doc.get("image"));
                sku.setCategoryName(doc.get("categoryName"));
                sku.setBrandName(doc.get("brandName"));
                sku.setSpec(doc.get("spec"));
                sku.setSaleNum(Integer.parseInt(Optional.ofNullable(doc.get("saleNum")).orElse("0")));
                skuList.add(sku);
            }
        }

        reader.close();
        return JSON.toJSONString(skuList);
    }


    @RequestMapping("/update")
    public String update() throws Exception {
        Sku sku = new LambdaQueryChainWrapper<>(skuBaseMapper).eq(Sku::getId, 1).one();
        Document document = new Document();
        /**
         * 是否分词：不分词，没有意义
         * 是否索引：索引
         * 是否存储：存储
         */
        document.add(new IntPoint("id", sku.getId().intValue()));
        document.add(new StoredField("id", sku.getId().intValue())); // ✅ 存储值
        /**
         * 是否分词：分词，因为分词后有意义
         * 是否索引：索引，需哟根据名称进行搜索
         * 是否存储：存储
         */
        document.add(new TextField("name", sku.getName(), Field.Store.YES)); // YES = 存储
        /**
         * 是否分词：分词，如果需要在lucene中进行范围查询，底层算法需要
         * 是否索引：索引
         * 是否存储：存储
         */

        int i = sku.getPrice() + new Random().nextInt(100);
        document.add(new IntPoint("price", i));
        // IntPoint 没有索引功能，所以需要单独存储
        document.add(new StoredField("price", i)); // ✅ 存储值
        /**
         *
         * StringField 不分词，索引，存储
         * 是否分词：不分词 ， 不需要根据路径搜索，StringField
         * 是否索引：可以索引，也可以不索引
         * 是否存储：存存储
         */
        document.add(new StringField("image", sku.getImage(), Field.Store.YES));
        /**
         * StringField 不分词，索引，存储
         * 是否分词：不分词 ， 类别一般就是枚举，不索引
         * 是否索引：可以索引，也可以不索引
         * 是否存储：存存储
         */
        document.add(new StringField("categoryName", sku.getCategoryName(), Field.Store.YES));
        /**
         * StringField 不分词，索引，存储
         * 是否分词：不分词 ， 品牌一般就是枚举，不索引
         * 是否索引：可以索引，也可以不索引
         * 是否存储：存存储
         */
        document.add(new StringField("brandName", sku.getBrandName(), Field.Store.YES));

        document.add(new StringField("spec", sku.getSpec(), Field.Store.YES));

        // saleNum 同理
        document.add(new IntPoint("saleNum", sku.getSaleNum()));
        document.add(new StoredField("saleNum", sku.getSaleNum())); // ✅ 存储值


        // 1. 指定索引存储路径
        Directory directory = FSDirectory.open(Paths.get(path));

        // 使用智能分词模式
        Analyzer analyzer = new IKAnalyzer(false);

        // 3. 配置 IndexWriter
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        // 4. 创建 IndexWriter
        IndexWriter writer = new IndexWriter(directory, config);


        /**
         * 修改id
         */
        Term term = new Term("id", sku.getId().toString());
        long l = writer.updateDocument(term, document);
        writer.close();
        return String.valueOf(l);
    }


    @RequestMapping("/delete")
    public String delete(@RequestParam("id") Long id) throws IOException {
        // 1. 指定索引目录
        Directory directory = FSDirectory.open(Paths.get(path));

        // 2. 使用 IKAnalyzer 分词器（与写入一致）
        Analyzer analyzer = new IKAnalyzer(false);

        // 3. 创建 IndexWriter 配置
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        config.setOpenMode(IndexWriterConfig.OpenMode.APPEND); // 只打开已有索引，不重建

        // 4. 创建 IndexWriter
        IndexWriter writer = new IndexWriter(directory, config);

        // 5. 构造 Term：基于 StringField("id", ...)
        Term term = new Term("id", String.valueOf(id));

        // 6. 执行删除
        long deletedCount = writer.deleteDocuments(term);

        // 7. 提交更改并关闭
        writer.commit(); // 提交事务
        writer.close();

        return "Deleted " + deletedCount + " document(s) with id=" + id;
    }
}
